package scatter.comment.rest.hierarchical.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;
import scatter.comment.pojo.hierarchical.form.*;
import scatter.comment.pojo.hierarchical.param.CommentHierarchicalForHierarchicalAddParam;
import scatter.comment.pojo.hierarchical.param.CommentHierarchicalForSubjectAddParam;
import scatter.comment.pojo.hierarchical.po.CommentHierarchical;
import scatter.comment.pojo.hierarchical.po.CommentHierarchicalStar;
import scatter.comment.pojo.hierarchical.vo.CommentHierarchicalAvailableVo;
import scatter.comment.rest.componentext.CommentHierarchicalAvailableExtProvider;
import scatter.comment.rest.componentext.CommentHierarchicalOnAddListener;
import scatter.comment.rest.hierarchical.mapper.CommentHierarchicalMapper;
import scatter.comment.rest.hierarchical.mapstruct.CommentHierarchicalMapStruct;
import scatter.comment.rest.hierarchical.mapstruct.CommentHierarchicalStarMapStruct;
import scatter.comment.rest.hierarchical.service.ICommentHierarchicalPicService;
import scatter.comment.rest.hierarchical.service.ICommentHierarchicalService;
import scatter.comment.rest.hierarchical.service.ICommentHierarchicalStarService;
import scatter.common.pojo.form.BasePageQueryForm;
import scatter.common.rest.service.IBaseAddUpdateQueryFormServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * <p>
 * 评论层级评论表 服务实现类
 * </p>
 *
 * @author yw
 * @since 2021-02-09
 */
@Service
@Transactional
public class CommentHierarchicalServiceImpl extends IBaseAddUpdateQueryFormServiceImpl<CommentHierarchicalMapper, CommentHierarchical, CommentHierarchicalAddForm, CommentHierarchicalUpdateForm, CommentHierarchicalPageQueryForm> implements ICommentHierarchicalService {

    @Autowired
    private ICommentHierarchicalPicService iCommentHierarchicalPicService;
    @Autowired
    private List<CommentHierarchicalOnAddListener> commentHierarchicalOnAddListenerList;
    @Autowired
    private ICommentHierarchicalStarService iCommentHierarchicalStarService;

    @Qualifier("commonDbTaskExecutor")
    @Autowired
    private ExecutorService executorService;

    @Autowired(required = false)
    private List<CommentHierarchicalAvailableExtProvider> commentHierarchicalAvailableExtProviders;

    @Override
    public void preAdd(CommentHierarchicalAddForm addForm,CommentHierarchical po) {
        super.preAdd(addForm,po);

    }

    @Override
    public void preUpdate(CommentHierarchicalUpdateForm updateForm,CommentHierarchical po) {
        super.preUpdate(updateForm,po);

    }

    @Override
    public Map<String, Page<CommentHierarchical>> listLatestCommentHierarchicalForPerSubject(List<String> subjectIds, Integer count, String groupFlag) {

        Assert.notEmpty(subjectIds,"subjectIds 不能为空");
        Assert.notNull(count,"count 不能为空");


        Map<String,Page<CommentHierarchical>> result = new HashMap<>();

        CompletableFuture[] completableFutures = subjectIds.stream().map(momentId -> CompletableFuture.supplyAsync(() -> {
            Page page = convertPage(new BasePageQueryForm().setCurrent(1L).setSize(Integer.toUnsignedLong(count)));
            page.setSearchCount(false);
            Page page1 = page(page, Wrappers.<CommentHierarchical>lambdaQuery()
                    .eq(CommentHierarchical::getSubjectId, momentId)
                    .eq(CommentHierarchical::getIsDisabled, false)
                    .eq(!isStrEmpty(groupFlag), CommentHierarchical::getGroupFlag, groupFlag)
                    .orderByDesc(CommentHierarchical::getTimeAt));
            return page1;
        }, executorService).whenComplete((r,e)->{result.put(momentId, (Page<CommentHierarchical>)r);})).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(completableFutures).join();
        return result;
    }

    @Override
    public CommentHierarchicalAvailableVo detailById(String id, String groupFlag, String loginUserId) throws InterruptedException {

        CommentHierarchical byId = getById(id);
        CommentHierarchicalAvailableVo commentHierarchicalAvailableVo = CommentHierarchicalMapStruct.INSTANCE.poToCommentHierarchicalAvailableVo(byId);

        fill(newArrayList(commentHierarchicalAvailableVo),groupFlag,loginUserId);

        return commentHierarchicalAvailableVo;
    }

    @Override
    public Map<String, Page<CommentHierarchical>> listLatestCommentHierarchicalForPerCommentHierarchical(List<String> commentHierarchicalIds, Integer count, String groupFlag) {
        Assert.notEmpty(commentHierarchicalIds,"commentHierarchicalIds 不能为空");
        Assert.notNull(count,"count 不能为空");


        Map<String,Page<CommentHierarchical>> result = new HashMap<>();

        CompletableFuture[] completableFutures = commentHierarchicalIds.stream().map(commentHierarchicalId -> CompletableFuture.supplyAsync(() -> {
            Page page = convertPage(new BasePageQueryForm().setCurrent(1L).setSize(Integer.toUnsignedLong(count)));
            page.setSearchCount(false);
            Page page1 = page(page, Wrappers.<CommentHierarchical>lambdaQuery()
                    .eq(CommentHierarchical::getParentId, commentHierarchicalId)
                    .eq(CommentHierarchical::getIsDisabled, false)
                    .eq(!isStrEmpty(groupFlag), CommentHierarchical::getGroupFlag, groupFlag)
                    .orderByDesc(CommentHierarchical::getTimeAt));
            return page1;
        }, executorService).whenComplete((r,e)->{result.put(commentHierarchicalId, (Page<CommentHierarchical>)r);})).toArray(CompletableFuture[]::new);
        // 等待所有异步执行完成
        CompletableFuture.allOf(completableFutures).join();
        return result;
    }

    @Override
    public IPage<CommentHierarchicalAvailableVo> listAvailableForSubjectPage(CommentHierarchicalAvailableForSubjectPageQueryForm pageQueryForm, String loginUserId) throws InterruptedException {
        Page<CommentHierarchical> page = page(convertPage(pageQueryForm), Wrappers.<CommentHierarchical>lambdaQuery()
                .eq(CommentHierarchical::getSubjectId, pageQueryForm.getSubjectId())
                .eq(CommentHierarchical::getIsDisabled, false)
                .eq(!isStrEmpty(pageQueryForm.getOwnerUserId()), CommentHierarchical::getOwnerUserId, pageQueryForm.getOwnerUserId())
                .eq(!isStrEmpty(pageQueryForm.getTargetUserId()), CommentHierarchical::getTargetUserId, pageQueryForm.getTargetUserId())
                .eq(!isStrEmpty(pageQueryForm.getGroupFlag()), CommentHierarchical::getGroupFlag, pageQueryForm.getGroupFlag())
                .orderByDesc(CommentHierarchical::getTimeAt).orderByDesc(CommentHierarchical::getId));

        return fillAndReturn(page,pageQueryForm.getGroupFlag(),loginUserId);
    }

    @Override
    public IPage<CommentHierarchicalAvailableVo> listAvailableForHierarchicalPage(CommentHierarchicalAvailableForHierarchicalPageQueryForm pageQueryForm, String loginUserId) throws InterruptedException {
        Page<CommentHierarchical> page = page(convertPage(pageQueryForm), Wrappers.<CommentHierarchical>lambdaQuery()
                .eq(CommentHierarchical::getParentId,pageQueryForm.getCommentHierarchicalId())
                .eq(CommentHierarchical::getIsDisabled,false)
                .eq(!isStrEmpty(pageQueryForm.getOwnerUserId()),CommentHierarchical::getOwnerUserId,pageQueryForm.getOwnerUserId())
                .eq(!isStrEmpty(pageQueryForm.getTargetUserId()),CommentHierarchical::getTargetUserId,pageQueryForm.getTargetUserId())
                .eq(!isStrEmpty(pageQueryForm.getGroupFlag()),CommentHierarchical::getGroupFlag,pageQueryForm.getGroupFlag())
                .orderByDesc(CommentHierarchical::getTimeAt).orderByDesc(CommentHierarchical::getId));

        return fillAndReturn(page,pageQueryForm.getGroupFlag(),loginUserId);

    }

    /**
     * 填充额外数据并返回
     * @param page
     * @param groupFlag
     * @param loginUserId
     * @return
     */
    private IPage<CommentHierarchicalAvailableVo> fillAndReturn(Page<CommentHierarchical> page,String groupFlag,String loginUserId) throws InterruptedException {
        IPage<CommentHierarchicalAvailableVo> commentSubjectAvailableVoIPage = CommentHierarchicalMapStruct.INSTANCE.pagePoCommentHierarchicalAvailableVo(page);
        fill(commentSubjectAvailableVoIPage.getRecords(),groupFlag,loginUserId);
        return commentSubjectAvailableVoIPage;
    }


    /**
     * 添加额外属性
     * @param commentHierarchicalVos
     * @param loginUserId
     */
    private void fill(List<CommentHierarchicalAvailableVo> commentHierarchicalVos, String groupFlag,String loginUserId) throws InterruptedException {

        int num = 3;
        if (!isEmpty(commentHierarchicalAvailableExtProviders)) {
            num += commentHierarchicalAvailableExtProviders.size();
        }

        // 下面是添加异步执行，加快提高性能
        CountDownLatch countDownLatch = new CountDownLatch(num);
        executorService.execute(()->{
            try {
                fillHasStared(commentHierarchicalVos,loginUserId);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestCommentHierarchicalStar(commentHierarchicalVos,10);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestCommentHierarchical(commentHierarchicalVos,5,groupFlag);
            } finally {
                countDownLatch.countDown();
            }
        });
        if (!isEmpty(commentHierarchicalAvailableExtProviders)) {
            for (CommentHierarchicalAvailableExtProvider commentHierarchicalAvailableExtProvider : commentHierarchicalAvailableExtProviders) {
                executorService.execute(()->{
                    try {
                        commentHierarchicalAvailableExtProvider.provideCommentHierarchical(commentHierarchicalVos);
                    } finally {
                        countDownLatch.countDown();
                    }
                });
            }
        }
        countDownLatch.await();
    }

    /**
     * 填充是否已点赞
     * @param commentHierarchicalVos
     * @param loginUserId
     */
    private void fillHasStared(List<CommentHierarchicalAvailableVo> commentHierarchicalVos,String loginUserId){
        if (isEmpty(commentHierarchicalVos) || loginUserId == null) {
            return;
        }
        Map<String, Boolean> stringBooleanMap = iCommentHierarchicalStarService.hasStared(commentHierarchicalVos.stream().map(CommentHierarchicalAvailableVo::getId).collect(Collectors.toList()), loginUserId);
        commentHierarchicalVos.forEach(item -> item.setIsMeHasStared(stringBooleanMap.get(item.getId())));

    }

    /**
     * 填充最新点赞数据
     * @param commentHierarchicalVos
     * @param count
     */
    private void fillLatestCommentHierarchicalStar(List<CommentHierarchicalAvailableVo> commentHierarchicalVos,Integer count){
        if (isEmpty(commentHierarchicalVos)) {
            return;
        }
        Map<String, Page<CommentHierarchicalStar>> stringPageMap = iCommentHierarchicalStarService.listLatestStarForPerCommentHierarchical(commentHierarchicalVos.stream().map(CommentHierarchicalAvailableVo::getId).collect(Collectors.toList()), count);
        for (CommentHierarchicalAvailableVo item : commentHierarchicalVos) {
            IPage iPage = CommentHierarchicalStarMapStruct.INSTANCE.pagePoToVo(stringPageMap.get(item.getId()));
            item.setLatestCommentHierarchicalStars(iPage);
        }
    }
    /**
     * 填充盖楼评论数据
     * @param commentHierarchicalVos
     * @param count
     */
    private void fillLatestCommentHierarchical(List<CommentHierarchicalAvailableVo> commentHierarchicalVos, Integer count, String groupFlag){
        Map<String, Page<CommentHierarchical>> stringPageMap =
                this.listLatestCommentHierarchicalForPerCommentHierarchical(commentHierarchicalVos.stream().map(CommentHierarchicalAvailableVo::getId).collect(Collectors.toList()), count,groupFlag);
        for (CommentHierarchicalAvailableVo item : commentHierarchicalVos) {
            IPage iPage = CommentHierarchicalMapStruct.INSTANCE.pagePoToVo(stringPageMap.get(item.getId()));
            item.setLatestCommentHierarchicals(iPage);
        }
    }

    @Override
    public CommentHierarchical addCommentHierarchicalForSubject(CommentHierarchicalForSubjectAddParam addParam) {

        Assert.hasText(addParam.getSubjectId(),"subjectId 不能为空");

        CommentHierarchical commentHierarchical = CommentHierarchicalMapStruct.INSTANCE.addParamForSubjectToPo(addParam);
        commentHierarchical.setCommentCount(0);
        // 楼层默认 1
        commentHierarchical.setFloor(Optional.ofNullable(addParam.getFloor()).orElse(1));
        commentHierarchical.setIsDisabled(false);
        commentHierarchical.setStarCount(0);
        commentHierarchical.setTimeAt(LocalDateTime.now());
        save(commentHierarchical);

        if (!isEmpty(addParam.getCommentHierarchicalPicUrls())) {
            iCommentHierarchicalPicService.addPics(addParam.getCommentHierarchicalPicUrls(), commentHierarchical.getId());
        }

        if (!isEmpty(commentHierarchicalOnAddListenerList)) {
            for (CommentHierarchicalOnAddListener commentHierarchicalOnAddListener : commentHierarchicalOnAddListenerList) {
                commentHierarchicalOnAddListener.postCommentHierarchicalForSubjectAdd(addParam,commentHierarchical);
            }
        }
        return commentHierarchical;
    }

    @Override
    public CommentHierarchical addCommentHierarchicalForHierarchical(CommentHierarchicalForHierarchicalAddParam addParam) {

        Assert.hasText(addParam.getCommentHierarchicalId(),"commentHierarchicalId 不能为空");

        CommentHierarchical commentHierarchical = CommentHierarchicalMapStruct.INSTANCE.addParamForHierarchicalToPo(addParam);
        commentHierarchical.setCommentCount(0);
        // 楼层默认 1
        commentHierarchical.setFloor(Optional.ofNullable(addParam.getFloor()).orElse(1));
        commentHierarchical.setIsDisabled(false);
        commentHierarchical.setStarCount(0);
        commentHierarchical.setTimeAt(LocalDateTime.now());

        // 盖楼，插入子级
        insertChild(commentHierarchical,addParam.getCommentHierarchicalId());

        if (!isEmpty(addParam.getCommentHierarchicalPicUrls())) {
            iCommentHierarchicalPicService.addPics(addParam.getCommentHierarchicalPicUrls(), commentHierarchical.getId());
        }

        if (!isEmpty(commentHierarchicalOnAddListenerList)) {
            for (CommentHierarchicalOnAddListener commentHierarchicalOnAddListener : commentHierarchicalOnAddListenerList) {
                commentHierarchicalOnAddListener.postCommentHierarchicalForHierarchicalAdd(addParam,commentHierarchical);
            }
        }
        return commentHierarchical;
    }
}
